`timescale 1ns / 1ns
`define	DATA_WIDTH	256
`define n_256r1 256'hFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551
`define n_sm2 256'hFFFFFFFE_FFFFFFFF_FFFFFFFF_FFFFFFFF_7203DF6B_21C6052B_53BBF409_39D54123


module signature(input clk,
				 input rst_n,
				 input curve_sel,
				 input enable_sign,				//签名
				 input enable_pair,				//密钥交换，da*P标量乘
				 //output reg end_flag,
				 //output reg [11:0] state,
				 //output reg [11:0] next_state,
				 output reg [10:0] state,
				 output reg [10:0] next_state,
				 input [`DATA_WIDTH-1:0] k,
				 input [`DATA_WIDTH-1:0] dA,	//密钥交换时k为私钥
				 input [`DATA_WIDTH-1:0] t1,	//最后s在这里
				 input [`DATA_WIDTH-1:0] t2,	//最后r在这里
				 input [`DATA_WIDTH-1:0] t3,
				 input [`DATA_WIDTH-1:0] t7,
				 output [`DATA_WIDTH-1:0] ss,	//第一次模n乘法中间结果
				 output [`DATA_WIDTH-1:0] s,	//第二次模n乘法中间结果
				 output [`DATA_WIDTH-1:0] r,
				 input   Hv_done,
				 //input sha512_done,
				 //input sm3_done,
				 input INV_end_flag,
				 input ML_end_flag,
				 output reg ML_enable,
				 output reg [21:0] r_sel,
				 //output reg [7:0] M_sel_a,
				 //output reg [7:0] M_sel_b,
				 output reg [7:0] A_sel_a,
				 output reg [7:0] A_sel_b,
				 output reg [1:0] I_sel,
				 output reg INV_enable,
				 output reg func,
				 output reg re_t1,				//给t1清零
				 output reg re_t7				//给t7清零
				 //output reg checks_no
				);

reg end_flag;

wire [`DATA_WIDTH-1:0] n;

reg [7:0] count;

wire [`DATA_WIDTH-1:0] II,H;

//wire [`DATA_WIDTH+1:0] s1,s2,s3,s4;

wire [`DATA_WIDTH+1:0] s1,s3;

wire [`DATA_WIDTH:0] s2,s4;

wire [`DATA_WIDTH:0] t71,t11;

reg swich_pair;

reg Hv_done_f;

//reg sha512_done_f;

//reg sm3_done_f;

parameter IDLE  = 11'b000_0000_0001,
		  CHOOSE= 11'b000_0000_0010,
		  KG    = 11'b000_0000_0100,
		  SM3   = 11'b000_0000_0101,
		  ADD_R = 11'b000_0000_0110,
		  CALUR = 11'b000_0000_1000,
		  CHECKR= 11'b000_0001_0000,
		  SHA   = 11'b000_0010_0000,
		  MUL   = 11'b000_0100_0000,
		  SUB_S = 11'b000_0100_0001,
		  ADD   = 11'b000_1000_0000,
		  INV   = 11'b001_0000_0000,
		  CALUS = 11'b010_0000_0000,
 		  CHECKS= 11'b100_0000_0000;
		  //FINAL = 12'b1000_0000_0000;
		  
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	begin
		state <= IDLE;
	end
	else
	begin
		state <= next_state;
	end
end

always @(*)
begin
	case(state)
	IDLE  : if((enable_sign == 1'b1)||(enable_pair == 1'b1))
				next_state = CHOOSE;
		    else
				next_state = IDLE;
	CHOOSE:	if(swich_pair == 1'b0)
				if((k<256'd1) || (k>n-1))
					next_state = IDLE;
				else
					next_state = KG;
			else
				if((dA<256'd1) || (dA>n-1))
					next_state = IDLE;
				else
					next_state = KG;
	KG    : if(curve_sel == 1'b0)
				//if((ML_end_flag) && (swich_pair == 1'b0))
				if(ML_end_flag)
					if(swich_pair == 1'b0)
						next_state = CALUR;
				//else if((ML_end_flag) && (swich_pair == 1'b1))
					else
						//next_state = FINAL;
						next_state = IDLE;
				else
					next_state = KG;
			else
				//if((ML_end_flag) && (swich_pair == 1'b0))
				if(ML_end_flag)
					if(swich_pair == 1'b0)
						next_state = SM3;
				//else if((ML_end_flag) && (swich_pair == 1'b1))
					else
						next_state = IDLE;
				else
					next_state = KG;
	SM3   :	if(Hv_done_f)
				next_state = ADD_R;
			else
				next_state = SM3;
	ADD_R : 	next_state = CHECKR;
	CALUR : 	next_state = CHECKR;
	CHECKR: if(curve_sel == 1'b0)
				if(t2!=256'b0)
					next_state = SHA;
				else
					next_state = IDLE;
			else
				if((t2==256'b0) || ((t2+k)==`n_sm2))
					next_state = IDLE;
				else
					next_state = MUL;
	SHA   : if(Hv_done_f)
				next_state = MUL;
			else
				next_state = SHA;
	MUL   : if(curve_sel == 1'b0)
				if(count == 10'd0)
					next_state = ADD;
				else
					next_state = MUL;
			else
				if(count == 10'd0)
					next_state = SUB_S;
				else
					next_state = MUL;
	SUB_S : 	next_state = ADD;
	ADD   : 	next_state = INV;
	INV   : if(INV_end_flag)
				next_state = CALUS;
			else
				next_state = INV;
	CALUS : if(count == 10'd0)
				next_state = CHECKS;
			else
				next_state = CALUS;
	/*CHECKS: if(t1!=0)
				next_state = FINAL;
			else
				next_state = IDLE;
    */
    CHECKS: 	next_state = IDLE;
	//FINAL : 	next_state = IDLE;
	default : next_state = IDLE;
	endcase
end

/*
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		checks_no <= 1'b0;
	else if((state == CHECKS) && (t1 == 256'h0))
		checks_no <= 1'b1;
	else
		checks_no <= 1'b0;
end
*/
/*
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		sha512_done_f <= 1'b0;
	else if(sha512_done)
		sha512_done_f <= 1'b1;
	else if((next_state == FINAL) || (next_state == IDLE))
		sha512_done_f <= 1'b0;
	else
		sha512_done_f <= sha512_done_f;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		sm3_done_f <= 1'b0;
	else if(sm3_done)
		sm3_done_f <= 1'b1;
	else if((next_state == FINAL) || (next_state == IDLE))
		sm3_done_f <= 1'b0;
	else
		sm3_done_f <= sm3_done_f;
end
*/

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		Hv_done_f <= 1'b0;
	else if(Hv_done)
		Hv_done_f <= 1'b1;
	//else if((next_state == FINAL) || (next_state == IDLE))
	else if(next_state == IDLE)
		Hv_done_f <= 1'b0;
	else
		Hv_done_f <= Hv_done_f;
end

always @(posedge clk or negedge rst_n)
begin	
	if(!rst_n)
		swich_pair <= 1'b0;
	else if(enable_pair)
		swich_pair <= 1'b1;
	else if(enable_sign)
		swich_pair <= 1'b0;
	//else if(next_state == FINAL)
	else if(next_state == IDLE)
		swich_pair <= 1'b0;
	else
		swich_pair <= swich_pair;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	begin
		count <= 8'd255;
	end
	else if((state == MUL) || (state == CALUS))
	begin
		count <= count - 1'b1;
	end
	else
	begin
		count <= 8'd255;
	end
end

always @(*)
begin
	case(state)
	ADD_R:
	begin
		//M_sel_a = 8'b0;
		//M_sel_b = 8'b0;
		A_sel_a = 8'b00000010;
		A_sel_b = 8'b00001000;
	end
	SUB_S:
	begin
		//M_sel_a = 8'b0;
		//M_sel_b = 8'b0;
		A_sel_a = 8'b00010000;
		A_sel_b = 8'b10000000;
	end
	ADD : 	
	begin
		if(curve_sel == 1'b0)
		begin
		//M_sel_a = 8'b0;
		//M_sel_b = 8'b0;
		A_sel_a = 8'b00000010;
		A_sel_b = 8'b10000000;
		end
		else
		begin
		//M_sel_a = 8'b0;
		//M_sel_b = 8'b0;
		A_sel_a = 8'b10000001;
		A_sel_b = 8'b10000001;
		end
	end
	default : 	
	begin
		//M_sel_a = 8'b0;
		//M_sel_b = 8'b0;
		A_sel_a = 8'b0;
		A_sel_b = 8'b0;
	end
	endcase
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		func <= 1'b0;
	//else if((state == MUL) && (next_state == SUB_S))
	else if(next_state == SUB_S)
		func <= 1'b1;
	else
		func <= 1'b0;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	begin
		INV_enable <= 1'b0;
	end
	//else if((state == ADD)&&(next_state == INV))
	else if(state == ADD)
	begin
		INV_enable <= 1'b1;
	end
	else
	begin
		INV_enable <= 1'b0;
	end
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	begin
		ML_enable <= 1'b0;
	end
	else if((state == CHOOSE) && (next_state == KG))
	begin
		ML_enable <= 1'b1;
	end
	else
	begin
		ML_enable <= 1'b0;
	end
end

always @(*)
begin
	case(state)
	INV : if(curve_sel == 1'b0)
			I_sel = 2'b10;
		  else
		    I_sel = 2'b01;
	default : I_sel = 2'b00;
	endcase
end

always @(*)
begin
	case(state)
	SM3   : r_sel = 22'b0000000000000000010100;
	ADD_R : r_sel = 22'b0000000010000000100000;
	CALUR : r_sel = 22'b0110000000000010100000;//为了清零t7
	CHECKR: if(curve_sel)
			r_sel = 22'b0110000000000000000000;
			else
			r_sel = 22'b0;
	SHA   : r_sel = 22'b0000000000000000010100;
	MUL   : r_sel = 22'b0110000000000000000000;
	SUB_S : r_sel = 22'b0010000000000000000000;
	ADD   : if(curve_sel == 1'b0)
			r_sel = 22'b0010000000000000000000;
			else
			r_sel = 22'b0000000000000100001100;
	INV   : if(curve_sel == 1'b0)
			r_sel = 22'b0000000000011100001100;//为了清零t1
			else
			if(INV_end_flag)
			r_sel = 22'b0000000000011100000000;
			else
			r_sel = 22'b0;
	CALUS : r_sel = 22'b0000000000000000001100;
	default : r_sel = 22'b0;
	endcase
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	re_t1 <= 1'b0;
	else if((next_state == INV) && (curve_sel == 1'b0))
	re_t1 <= 1'b1;
	//else if((next_state == ADD) && (state == SUB_S) && (curve_sel == 1'b1))
	//else if((state == SUB_S) && (next_state == ADD))
	else if((next_state == ADD) && (curve_sel == 1'b1))
	re_t1 <= 1'b1;
	else
	re_t1 <= 1'b0;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	re_t7 <= 1'b0;
	//else if((next_state == CALUR) && (curve_sel == 1'b0))
	else if(next_state == CALUR)
	re_t7 <= 1'b1;
	//else if((next_state == CHECKR) && (state == ADD_R) && (curve_sel == 1'b1))
	else if((next_state == CHECKR) && (curve_sel == 1'b1))
	re_t7 <= 1'b1;
	else
	re_t7 <= 1'b0;
end

assign n = (curve_sel == 1'b0) ? `n_256r1: `n_sm2;

assign r = (t3 > n) ? (t3 - n) : t3;

assign II = (t2[count] == 1) ? dA : 0;

assign t71 = t7<<1;

assign s1 =  t71 + II;

assign s2 = (s1 >= {2'b00,n}) ? s1 - n : s1;

assign ss = (s2 >= {2'b00,n}) ? s2 - n  : s2;

assign H = (t3[count] == 1) ? t7 : 0;

assign t11 = t1<<1;

assign s3 = t11 + H;

assign s4 = (s3 >= {2'b00,n}) ? s3 - n : s3;

assign s = (s4 >= {2'b00,n}) ? s4 - n : s4;


always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	begin
		end_flag <= 1'b0;
	end
	else if(next_state == IDLE)
	begin
		end_flag <= 1'b1;
	end
	else
	begin
		end_flag <= 1'b0;
	end
end


endmodule
